#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
from flask import Flask, jsonify, request
import requests


app = Flask(__name__, static_url_path='/')

# [[[2-1]]]
### 填写WeBASE-Front地址，用于后续交互
URL = 'http://192.168.0.105:5002/WeBASE-Front/trans/handle'

### 填写智能合约的相关信息
CONTRACT_NAME = 'Trace'
CONTRACT_ADDRESS = '0x85ccc6776cc898ef3ea706275789a2f2804c0244'
CONTRACT_ABI = '[{"constant":false,"inputs":[],"name":"ProducersRemove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"DistributorRemove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"traceNumber","type":"uint256"}],"name":"getFood","outputs":[{"name":"","type":"uint256"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"address"},{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"traceNumber","type":"uint256"}],"name":"getTraceInfo","outputs":[{"name":"","type":"uint256[]"},{"name":"","type":"string[]"},{"name":"","type":"address[]"},{"name":"","type":"uint8[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"name","type":"string"},{"name":"traceNumber","type":"uint256"},{"name":"traceName","type":"string"},{"name":"quality","type":"uint8"}],"name":"newFood","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"ProducersAdd","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"traceNumber","type":"uint256"},{"name":"traceName","type":"string"},{"name":"quality","type":"uint8"}],"name":"addTraceInfoByDistributor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isRetailer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllFood","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isDistributor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isProducers","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"RetailerRemove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"traceNumber","type":"uint256"},{"name":"traceName","type":"string"},{"name":"quality","type":"uint8"}],"name":"addTraceInfoByRetailer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"RetailerAdd","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"DistributorAdd","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"producers","type":"address"},{"name":"distributor","type":"address"},{"name":"retailer","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"RetailerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"RetailerRemoves","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"DistributorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"DistributorRemoves","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"ProducersAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"ProducersRemoves","type":"event"}]'

### 填写用户地址信息
PRODUCER_ADDRESS = '0xbb8c30d7afc6eb8ef8061f2b16be8555c73afa26'
DISTRIBUTOR_ADDRESS = '0x537c65c98ddae086666a86477be35ca9c733aef3'
RETAILER_ADDRESS = '0x1abad964b3964801ea5bafc309a9c9e29544529a'


@app.route('/', methods=['GET'])
def index():
    return app.send_static_file("index.html")


# 获取用户地址
# userinfo: 用户角色（producer=农场 distributor=中间商 retailer=超市）
# return: 角色对应用户地址
@app.route('/userinfo', methods=['GET'])
def user_info():
    # 返回各个用户的地址
    user_name = request.args.get("userName")
    if user_name == 'producer':
        return jsonify({'address': PRODUCER_ADDRESS})
    elif user_name == 'distributor':
        return jsonify({'address': DISTRIBUTOR_ADDRESS})
    elif user_name == 'retailer':
        return jsonify({'address': RETAILER_ADDRESS})
    else:
        return 'user not found', 404

# 添加食品生产信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# foodName: 食物名称
# traceName: 用户名，食品流转过程各个阶段的用户名
# quality: 当前食品质量（0=优质 1=合格 2=不合格）
# return：添加食品生产信息结果
@app.route('/produce', methods=["POST"])
def produce():
    # 生产商生产食品
    body = request.get_data()
    if not body:
        return 'invalid parameter', 404
    body = json.loads(body.decode())
    trace_number = body.get("traceNumber")
    food_name = body.get("foodName")
    trace_name = body.get("traceName")
    quality = body.get("quality")

    params = [food_name, trace_number, trace_name, quality]
    payload = json.dumps(
        {'contractName': CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": PRODUCER_ADDRESS, "funcName": "newFood", "funcParam": params})
    headers = {'Content-Type': 'application/json'}
    result = requests.post(URL, headers=headers, data=payload)
    msg = json.loads(result.content.decode())["message"]
    if msg is None:
        return jsonify({'ret': 1, 'msg': msg})
    else:
        return jsonify({'ret': 0, 'msg': msg})

# 中间商添加食品流转信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# traceName: 用户名，食品流转过程各个阶段的用户名
# quality: 当前食品质量（0=优质 1=合格 2=不合格）
# return：中间商添加食品流转信息结果
@app.route('/adddistribution', methods=["POST"])
def add_trace_by_distrubutor():
    body = request.get_data()
    if not body:
        return 'invalid parameter', 404
    body = json.loads(body.decode())

    trace_number = body.get("traceNumber")
    trace_name = body.get("traceName")
    quality = body.get("quality")

    params = [trace_number, trace_name, quality]
    payload = json.dumps(
        {'contractName': CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": DISTRIBUTOR_ADDRESS, "funcName": "addTraceInfoByDistributor", "funcParam": params})

    headers = {'Content-Type': 'application/json'}
    result = requests.post(URL, headers=headers, data=payload)
    msg = json.loads(result.content.decode())["message"]
    if msg is None:
        return jsonify({'ret': 1, 'msg': msg})
    else:
        return jsonify({'ret': 0, 'msg': msg})

# 超市添加食品流转信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# traceName: 用户名，食品流转过程各个阶段的用户名
# quality: 当前食品质量（0=优质 1=合格 2=不合格）
# return：超市添加食品流转信息结果
@app.route('/addretail', methods=["POST"])
def add_trace_by_retailer():
    body = request.get_data()
    if not body:
        return 'invalid parameter', 404
    body = json.loads(body.decode())

    trace_number = body.get("traceNumber")
    trace_name = body.get("traceName")
    quality = body.get("quality")

    headers = {'Content-Type': 'application/json'}
    params = [trace_number, trace_name, quality]
	# [[[2-2]]]补充超市添加食品流转信息上链的逻辑
    payload = json.dumps({
        'contractName': CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
        "user": RETAILER_ADDRESS, "funcName": "addTraceInfoByRetailer", "funcParam": params
    })
    result = requests.post(URL, headers=headers, data=payload)
    msg = json.loads(result.content.decode())["message"]
    if msg is None:
        return jsonify({'ret': 1, 'msg': msg})
    else:
        return jsonify({'ret': 0, 'msg': msg})

# 获取所有食物信息
# return: 所有食品信息列表
@app.route('/foodlist', methods=["GET"])
def getlist():
    num_list = get_food_list()
    num_list = num_list[0]
    res = []
    for num in num_list:
        food = get_food(num)
        res.append(food)
    return jsonify(res)

# 获取某个食品的溯源信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# return: 对应食品的溯源信息
@app.route('/trace', methods=["GET"])
def trace():
    trace_number = request.args.get("traceNumber", type=int)
    if not trace_number:
        return 'invalid parameter', 404
    res = get_trace(trace_number)
    return jsonify(res)

# 获取某个食品的当前信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# return: 对应食品的当前信息
@app.route('/food', methods=["GET"])
def food():
    trace_number = request.args.get("traceNumber", type=int)
    if not trace_number:
        return 'invalid parameter', 404
    res = get_food(trace_number)
    return jsonify(res)

# 获取所有食品的最新溯源信息
# return: 所有食品的最新溯源信息
@app.route('/newtracelist', methods=["GET"])
def get_latest():
    num_list = get_food_list()
    num_list = num_list[0]
    res = []
    for num in num_list:
        trace = get_trace(num)
        res.append(trace[-1])
    return jsonify(res)

# 获取位于生产商的的食物信息
# return: 所有位于生产商的食品信息列表
@app.route('/producing', methods=["GET"])
def get_producing():
    num_list = get_food_list()
    num_list = num_list[0]
    res = []
    for num in num_list:
        trace = get_trace(num)
        if len(trace) == 1:
            res.append(trace[0])
    return jsonify(res)

# 获取位于中间商的食物信息
# return: 所有位于中间商的食品信息列表
@app.route('/distributing', methods=["GET"])
def get_distributing():
    num_list = get_food_list()
    num_list = num_list[0]
    res = []
    for num in num_list:
        trace = get_trace(num)
        if len(trace) == 2:
            res.append(trace[1])
    return jsonify(res)

# 获取位于超市的食物信息
# return: 所有位于超市的食品信息列表
@app.route('/retailing', methods=["GET"])
def get_retailing():
    num_list = get_food_list()
    num_list = num_list[0]
    res = []
    for num in num_list:
        trace = get_trace(num)
        if len(trace) == 3:
            res.append(trace[2])
    return jsonify(res)

# 从链上获取所有食品信息
# return: 所有食品信息列表
def get_food_list():
    payload = json.dumps(
        {"contractName": CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": "", "funcName": "getAllFood"})
    headers = {'Content-Type': 'application/json'}
    r = requests.post(URL, headers=headers, data=payload)
    return json.loads(r.content.decode())

# 从链上获取某个食品的基本信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# return: 对应食品的信息
def get_food(trace_number):
    params = [trace_number]
    payload = json.dumps(
        {"contractName": CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": "", "funcName": "getFood", "funcParam": params})
    headers = {'Content-Type': 'application/json'}
    result = requests.post(URL, headers=headers, data=payload)
    food = json.loads(result.content.decode())
    return {"traceNumber": trace_number, "timestamp": food[0], "produce": food[1], "name": food[2], "current": food[3],
            "address": food[4], "quality": food[5]}

# 从链上获取某个食品的溯源信息
# traceNumber: 食品溯源id，食品溯源过程中的标识符
# return: 对应食品的溯源信息
def get_trace(traceNumber):
    # 获取食品基本信息
    params = [traceNumber]
    headers = {'Content-Type': 'application/json'}
    payload = json.dumps(
        {"contractName": CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": "", "funcName": "getFood", "funcParam": params})
    result = requests.post(URL, headers=headers, data=payload)
    food = json.loads(result.content.decode())

    ### 获取食品溯源信息
    payload = json.dumps(
        {"contractName": CONTRACT_NAME, "contractAddress": CONTRACT_ADDRESS, "contractAbi": json.loads(CONTRACT_ABI),
         "user": "", "funcName": "getTraceInfo", "funcParam": params})
    result = requests.post(URL, headers=headers, data=payload)
    res = []
    time_list, name_list, address_list, quality_list = json.loads(result.content.decode())
    for i in range(len(time_list)):
        if i == 0:
            res.append({"traceNumber": traceNumber, "name": food[2], "produce_time": food[0], "timestamp": time_list[i],
                        "from": name_list[i], "quality": quality_list[i], "from_address": address_list[i]})
        else:
            res.append({"traceNumber": traceNumber, "name": food[2], "produce_time": food[0], "timestamp": time_list[i],
                        "from": name_list[i - 1], "to": name_list[i], "quality": quality_list[i],
                        "from_address": address_list[i - 1], "to_address": address_list[i]})
    return res


if __name__ == '__main__':
    # [[[1-7]]]
    ### 填写host和port，要求port为30+组号，如3001
    app.run(host="0.0.0.0", port="3021")
